home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c
- Path: news.sprintlink.net!eskimo!scs
- From: scs@eskimo.com (Steve Summit)
- Subject: Re: void ** question
- X-Nntp-Posting-Host: eskimo.com
- Message-ID: <DoML1s.BEC@eskimo.com>
- Sender: news@eskimo.com (News User Id)
- Organization: schmorganization
- References: <DoJBrL.F5t@bear.wn.bawue.de>
- Date: Thu, 21 Mar 1996 16:13:04 GMT
-
- In article <DoJBrL.F5t@bear.wn.bawue.de>, jo@bear.wn.bawue.de
- (Joerg Sommrey) writes:
- > I have a question concerning conversion to `void **'.
- >...
- > On four platforms I get three results: silence, warning and error...
- >
- > The FAQ states there isn't a portable way of calling a function with a
- > generic pointer by reference. This seems to be the point but I do not
- > understand why.
-
- The book-length version of the FAQ list (ask me for details)
- explains at some length:
-
- 4.9: Suppose I want to write a function that takes a generic pointer
- as an argument and I want to simulate passing it by reference.
- Can I give the formal parameter type void **, and do something
- like this?
-
- void f(void **);
- double *dp;
- f((void **)&dp);
-
- A: Not portably. Code like this may work and is sometimes
- recommended, but it relies on all pointer types having the same
- internal representation (which is common, but not universal; see
- question 5.17).
-
- There is no generic pointer-to-pointer type in C. void * acts
- as a generic pointer only because conversions are applied
- automatically when other pointer types are assigned to and from
- void *'s; these conversions cannot be performed if an attempt is
- made to indirect upon a void ** value which points at something
- other than a void *. When you make use of a void ** pointer
- value (for instance, when you use the * operator to access the
- void * value to which the void ** points), the compiler has no
- way of knowing whether that void * value was once converted from
- some other pointer type. It must assume that it is nothing more
- than a void *; it cannot perform any implicit conversions.
-
- In other words, any void ** value you play with must be the
- address of an actual void * value somewhere; casts like
- (void **)&dp, though they may shut the compiler up, are
- nonportable (and may not even do what you want; see also
- question 13.9). If the pointer that the void ** points to is
- not a void *, and if it has a different size or representation
- than a void *, then the compiler isn't going to be able to
- access it correctly.
-
- To make the code fragment above work, you'd have to use an
- intermediate void * variable:
-
- double *dp;
- void *vp = dp;
- f(&vp);
- dp = vp;
-
- The assignments to and from vp give the compiler the opportunity
- to perform any conversions, if necessary.
-
- Again, the discussion so far assumes that different pointer
- types might have different sizes or representations, which is
- rare today, but not unheard of. To appreciate the problem with
- void ** more clearly, compare the situation to an analogous one
- involving, say, types int and double, which probably have
- different sizes and certainly have different representations.
- If we have a function
-
- void incme(double *p)
- {
- *p += 1;
- }
-
- then we can do something like
-
- int i = 1;
- double d = i;
- incme(&d);
- i = d;
-
- and i will be incremented by 1. (This is analogous to the
- correct void ** code involving the auxiliary vp.) If, on the
- other hand, we were to attempt something like
-
- int i = 1;
- incme((double *)&i); /* WRONG */
-
- (this code is analogous to the fragment in the question), it
- would be highly unlikely to work.
-
-
- Jo went on to ask:
- > My questions:
- > 1) Is `(void **) ppi' legal (which makes any tested compiler shut up)?
-
- I hope the above discussion shows that it is not.
-
- (Also, by the way, I hope that no one objects to these excerpts
- I sometimes post as being ads, although of course I'd love it if
- y'all bought a copy.)
-
- > 3) Are any of these compilers broken?
-
- Since it's undefined what happens when you use an explicit cast
- to perform a nonportable pointer conversion (or when you pass an
- incompatible argument to an unprototyped function, although Jo's
- example code didn't do that), it's perfectly legal for a compiler
- to accept it, warn about it, or reject it.
-
- Steve Summit
- scs@eskimo.com
- --
- The Communications Decency Act within the Telecommunications Act
- of 1996 (U.S.) is an annoying, threatening, abusive, indecent,
- and obscene piece of legislation which attempts to ban annoying,
- threatening, abusive, indecent, or obscene communication.
-